package cn.edu.tju.wallet.service;

import cn.edu.tju.core.model.User;
import cn.edu.tju.core.security.repository.UserRepository;
import cn.edu.tju.wallet.domain.VirtualWallet;
import cn.edu.tju.wallet.domain.OverdraftRule;
import cn.edu.tju.wallet.domain.Transaction;
import cn.edu.tju.wallet.domain.Transaction.TransactionType;
import cn.edu.tju.wallet.repository.OverdraftRuleRepository;
import cn.edu.tju.wallet.repository.TransactionRepository;
import cn.edu.tju.wallet.repository.VirtualWalletRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;

/**
 * 透支服务
 * @author 付佳腾
 */
@Service
public class OverdraftService {

    @Autowired
    private VirtualWalletRepository walletRepository;

    @Autowired
    private OverdraftRuleRepository overdraftRuleRepository;

    @Autowired
    private TransactionRepository transactionRepository;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private VipLevelService vipLevelService;

    /**
     * 透支功能
     * @param userId 用户ID
     * @param amount 透支金额
     */
    @Transactional
    public void overdraft(Long userId, BigDecimal amount) {
        // 1. 查询钱包
        VirtualWallet wallet = walletRepository.findByUserId(userId)
                .orElseThrow(() -> new RuntimeException("钱包不存在，请先充值开通钱包"));

        // 2. 查询透支规则（根据VIP等级）
        OverdraftRule rule = overdraftRuleRepository
                .findFirstByStatusAndMinVipLevelLessThanEqualOrderByMinVipLevelDesc(
                        OverdraftRule.RuleStatus.ACTIVE, wallet.getVipLevel())
                .orElseThrow(() -> new RuntimeException("不符合透支条件：VIP等级不足或规则不存在"));

        // 3. 获取用户VIP等级信息
        User user = userRepository.findById(userId).orElse(null);
        BigDecimal overdraftMultiplier = BigDecimal.ONE;  // 默认无倍数
        if (user != null && user.getVipLevelValue() != null && user.getVipLevelValue() > 0) {
            var vipLevelOpt = vipLevelService.getVipLevelByLevel(user.getVipLevelValue());
            if (vipLevelOpt.isPresent()) {
                var vipLevelDTO = vipLevelOpt.get();
                if (vipLevelDTO.getOverdraftMultiplier() != null) {
                    overdraftMultiplier = vipLevelDTO.getOverdraftMultiplier();
                }
            }
        }

        // 4. 计算VIP增强后的透支限额
        BigDecimal baseOverdraftLimit = rule.getOverdraftLimit();
        BigDecimal vipOverdraftLimit = baseOverdraftLimit.multiply(overdraftMultiplier);

        // 5. 记录透支前余额
        BigDecimal balanceBefore = wallet.getBalance();
        BigDecimal overdraftAmountBefore = wallet.getOverdraftAmount();

        // 6. 更新钱包的透支额度（应用VIP倍数）
        wallet.setOverdraftLimit(vipOverdraftLimit);

        // 7. 执行透支（调用领域模型）
        wallet.overdraft(amount, rule);

        // 8. 保存钱包
        walletRepository.save(wallet);

        // 9. 记录交易流水
        Transaction transaction = new Transaction(
                wallet.getId(),
                TransactionType.OVERDRAFT,
                amount,
                balanceBefore,
                wallet.getBalance()
        );

        // 构建备注信息，包含VIP特权说明
        String remark = String.format("透支: %s, 基础额度: %s", amount, baseOverdraftLimit);
        if (overdraftMultiplier.compareTo(BigDecimal.ONE) > 0) {
            remark += String.format(", VIP倍数: %s, 实际额度: %s", overdraftMultiplier, vipOverdraftLimit);
        }
        remark += String.format(", 已透支金额: %s -> %s", overdraftAmountBefore, wallet.getOverdraftAmount());

        transaction.setRemark(remark);
        transactionRepository.save(transaction);
    }

    /**
     * 还款功能
     * 注意：还款金额从钱包可用余额中扣除
     * @param userId 用户ID
     * @param amount 还款金额
     * @return 还款结果
     */
    @Transactional
    public VirtualWallet.RepayResult repay(Long userId, BigDecimal amount) {
        // 1. 查询钱包
        VirtualWallet wallet = walletRepository.findByUserId(userId)
                .orElseThrow(() -> new RuntimeException("钱包不存在，请先充值开通钱包"));

        // 2. 检查是否有透支金额
        if (wallet.getOverdraftAmount().compareTo(BigDecimal.ZERO) == 0) {
            throw new IllegalStateException("无透支金额，无需还款");
        }

        // 3. 查询透支规则
        OverdraftRule rule = overdraftRuleRepository
                .findFirstByStatusAndMinVipLevelLessThanEqualOrderByMinVipLevelDesc(
                        OverdraftRule.RuleStatus.ACTIVE, wallet.getVipLevel())
                .orElseThrow(() -> new RuntimeException("透支规则不存在"));

        // 4. 获取用户VIP等级信息（用于利息折扣）
        User user = userRepository.findById(userId).orElse(null);
        BigDecimal interestDiscount = BigDecimal.ONE;  // 默认无折扣
        String vipLevelName = "普通用户";
        if (user != null && user.getVipLevelValue() != null && user.getVipLevelValue() > 0) {
            var vipLevelOpt = vipLevelService.getVipLevelByLevel(user.getVipLevelValue());
            if (vipLevelOpt.isPresent()) {
                var vipLevelDTO = vipLevelOpt.get();
                if (vipLevelDTO.getInterestDiscount() != null) {
                    interestDiscount = vipLevelDTO.getInterestDiscount();
                }
                vipLevelName = vipLevelDTO.getName();
            }
        }

        // 5. 记录还款前状态
        BigDecimal balanceBefore = wallet.getBalance();
        BigDecimal availableBalanceBefore = wallet.getAvailableBalance();
        BigDecimal overdraftAmountBefore = wallet.getOverdraftAmount();

        // 6. 计算利息（先计算基础利息，再应用VIP折扣）
        BigDecimal baseInterest = wallet.calculateInterest(overdraftAmountBefore, rule);
        BigDecimal discountedInterest = baseInterest.multiply(interestDiscount);
        BigDecimal totalDebt = overdraftAmountBefore.add(discountedInterest);

        // 7. 确定实际还款金额
        // 实际还款金额 = min(用户请求金额, 总债务, 可用余额)
        // - 不能超过总债务：用户只能还清总债务，多余部分不扣除
        // - 不能超过可用余额：用户只能使用可用余额还款，不能透支还款
        BigDecimal actualRepayAmount = amount;
        if (actualRepayAmount.compareTo(totalDebt) > 0) {
            actualRepayAmount = totalDebt; // 限制为总债务
        }
        if (actualRepayAmount.compareTo(availableBalanceBefore) > 0) {
            actualRepayAmount = availableBalanceBefore; // 限制为可用余额
        }

        // 8. 检查是否有可用余额
        if (actualRepayAmount.compareTo(BigDecimal.ZERO) <= 0) {
            throw new IllegalStateException(
                    String.format("可用余额不足，无法还款。总债务: %s, 可用余额: %s",
                            totalDebt, availableBalanceBefore));
        }

        // 9. 执行还款（调用领域模型，处理透支金额和利息计算）
        VirtualWallet.RepayResult result = wallet.repay(actualRepayAmount, rule);

        // 10. 从可用余额和总余额中扣除实际还款金额
        wallet.setAvailableBalance(availableBalanceBefore.subtract(actualRepayAmount));
        wallet.setBalance(balanceBefore.subtract(actualRepayAmount));

        // 11. 保存钱包
        walletRepository.save(wallet);

        // 12. 记录交易流水
        Transaction transaction = new Transaction(
                wallet.getId(),
                TransactionType.REPAY,
                actualRepayAmount.negate(), // 还款是支出，使用负数
                balanceBefore,
                wallet.getBalance()
        );
        // 构建交易流水备注信息
        String remark = String.format("还款: %s, VIP等级: %s, 本金: %s",
                actualRepayAmount, vipLevelName, result.getRepaidPrincipal());

        // 添加利息信息，包含折扣说明
        if (interestDiscount.compareTo(BigDecimal.ONE) < 0) {
            remark += String.format(", 基础利息: %s, VIP折扣: %s%%, 实际利息: %s",
                    baseInterest,
                    interestDiscount.multiply(BigDecimal.valueOf(100)),
                    discountedInterest);
        } else {
            remark += String.format(", 利息: %s", discountedInterest);
        }

        remark += String.format(", 剩余透支: %s (已透支: %s -> %s)",
                result.getRemainingOverdraft(),
                overdraftAmountBefore,
                wallet.getOverdraftAmount());

        // 如果用户请求的金额超过总债务，在备注中说明（实际只还了总债务）
        if (amount.compareTo(totalDebt) > 0) {
            BigDecimal excess = amount.subtract(totalDebt);
            remark += String.format(", 请求金额: %s, 实际还款: %s, 多余金额: %s (未扣除)",
                    amount, actualRepayAmount, excess);
        }

        // 如果用户请求的金额超过可用余额，在备注中说明（实际只用了可用余额）
        if (amount.compareTo(availableBalanceBefore) > 0 && actualRepayAmount.compareTo(availableBalanceBefore) == 0) {
            remark += String.format(", 请求金额: %s, 可用余额: %s, 实际还款: %s",
                    amount, availableBalanceBefore, actualRepayAmount);
        }

        transaction.setRemark(remark);
        transactionRepository.save(transaction);

        return result;
    }
}